#ifndef _GALOIS_ADD_H
#define _GALOIS_ADD_H

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

/*  w == 8 implementations:
	full tables (galois.c)
	lazy logtable (only one row in memory at a time)
	log/antilog

	(also composite k == 2)
	*/

void galois_w08_log_region_multiply(unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_w08_lazytable_region_multiply(unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_composite_w08_region_mult_k2 (unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

/*  w == 16 implementations:
	log/antilog (galois.c)
	lazytable
	composite k == 2
	split composite k == 2
	*/

void galois_w16_lazytable_region_multiply(unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_composite_w16_region_mult_k2 (unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_split_composite_w16_region_mult_k2 (unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

/*  w == 32 implementations:
	split w8 tables (galois.c)
	lazy split w8 tables
	composite k == 2
	composite k == 4
	split composite k == 2
	split composite k == 4
	composite 8 ^ 2 ^ 2
	*/

void galois_w32_lazy_split_region_multiply(unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_composite_w32_region_mult_k2 (unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_composite_w32_region_mult_k4 (unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_split_composite_w32_region_mult_k2 (unsigned char *region,
		int multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_split_composite_w32_region_mult_k4 (unsigned char *region,
		uint32_t multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_w32_composite_region_mult_k22 (unsigned char *region,
		uint32_t multby,
		int nbytes,
		unsigned char *r2,
		int add);

/*  w == 64 implementations:
	split w8 tables
	lazy split w8 tables
	composite k == 2  (using split for l == 32)
	***composite k == 2  (using composite k == 2, l == 16)
	composite k == 4
	*/

void galois_w64_split_region_multiply (unsigned char *region,
		uint64_t multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_w64_lazy_split_region_multiply (unsigned char *region,
		uint64_t multby,
		int nbytes,
		unsigned char *r2,
		int add);

void galois_w64_composite_k2_region_multiply (unsigned char *region,
		uint64_t multby,
		int nbytes,
		unsigned char *r2,
		int add);

/*  w == 128
	composite k == 2 (using split table for l == 64)
	composite k == 4 (waiting for PP from Kevin)
	***composite k == 2 (using composite k == 2, l == 32)
	*/

uint64_t galois_composite_multiply_k4 (uint64_t a, uint64_t b, uint64_t n);
uint64_t galois_composite_divide_k4 (uint64_t a, uint64_t b, uint64_t n);
uint64_t galois_composite_inverse_k4 (uint64_t a, uint64_t n);

uint32_t galois_composite_w8_multiply_k2 (uint32_t a, uint32_t b, uint32_t n);

uint64_t galois_composite_multiply_k22 (uint64_t a, uint64_t b, uint64_t n);
uint64_t galois_composite_divide_k22 (uint64_t a, uint64_t b, uint64_t n);
uint64_t galois_composite_inverse_k22 (uint64_t a, uint64_t n);

uint64_t galois_composite_multiply_k2 (uint64_t a, uint64_t b, uint64_t n/*, uint64_t s*/);
uint64_t galois_composite_divide_k2 (uint64_t a, uint64_t b, uint64_t n/*, uint64_t s*/);
uint64_t galois_composite_inverse_k2 (uint64_t a, uint64_t n/*, uint64_t s*/);

uint64_t galois_shift_multiply_w64 (uint64_t x, uint64_t y);
uint64_t galois_shift_divide_w64 (uint64_t x, uint64_t y);

uint64_t galois_create_split_w64 ();
uint64_t galois_split_multiply_w64 (uint64_t x, uint64_t y);
uint64_t galois_split_divide_w64 (uint64_t x, uint64_t y);

uint64_t galois_shift_inverse_w64 (uint64_t x);

uint64_t *galois_shift_multiply_w128 (uint64_t *x, uint64_t *y);
uint64_t *galois_shift_divide_w128 (uint64_t *x, uint64_t *y);

int galois_create_split_w128 ();
uint64_t *galois_split_multiply_w128 (uint64_t *x, uint64_t *y);
uint64_t *galois_split_divide_w128 (uint64_t *x, uint64_t *y);

uint64_t *galois_shift_inverse_w128 (uint64_t *x);

void print_big (uint64_t a, int size);

#endif
